<script lang="ts">
  export default {
    name: 'role',
  };
</script>

<template>
  <div class="app-container">
    <!-- 搜索表单 -->
    <el-form ref="queryFormRef" :model="queryParams" :inline="true">
      <el-form-item>
        <el-button
          type="success"
          :icon="Plus"
          @click="handleAdd"
          v-hasPerm="[POST + AUTH_PATH_WEB_PREFIX + '/role']"
        >新增
        </el-button>
        <el-button
          type="danger"
          :icon="Delete"
          :disabled="multiple"
          @click="handleDelete"
          v-hasPerm="[DELETE + AUTH_PATH_WEB_PREFIX + '/role/list']"
        >删除
        </el-button
        >
      </el-form-item>

      <el-form-item prop="name">
        <el-input
          v-model="queryParams.name"
          placeholder="角色名称"
          clearable
          @keyup.enter="handleQuery"
        />
      </el-form-item>

      <el-form-item>
        <el-button
          type="primary"
          :icon="Search"
          @click="handleQuery"
          v-hasPerm="[DELETE + AUTH_PATH_WEB_PREFIX + '/role/page']"
        >搜索</el-button>
        <el-button
          :icon="Refresh"
          @click="resetQuery"
          v-hasPerm="[DELETE + AUTH_PATH_WEB_PREFIX + '/role/page']"
        >重置
        </el-button>
      </el-form-item>
    </el-form>

    <!-- 数据表格 -->
    <el-table
      ref="dataTableRef"
      v-loading="loading"
      :data="roleList"
      @selection-change="handleSelectionChange"
      @row-click="handleRowClick"
      highlight-current-row
      border
      v-hasPerm="[GET + AUTH_PATH_WEB_PREFIX + '/user/page']"
    >
      <el-table-column type="selection" width="55" align="center"/>
      <el-table-column label="名称" prop="name"/>
      <el-table-column label="编码" prop="authCode"/>
      <el-table-column label="排序" prop="sort"/>
      <el-table-column label="状态" align="center">
        <template #default="scope">
          <el-tag v-if="scope.row.enabled" type="success">启用</el-tag>
          <el-tag v-else type="info">停用</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="200"
         v-hasPerm="[
                PUT + AUTH_PATH_WEB_PREFIX + '/role/{id}/link'
                , PUT + AUTH_PATH_WEB_PREFIX + '/role/{id}'
                , DELETE + AUTH_PATH_WEB_PREFIX + '/role/list'
              ]"
      >
        <template #default="scope">
          <el-button
            type="primary"
            circle
            plain
            @click.stop="handleResourceAssign(scope.row)"
            v-hasPerm="[PUT + AUTH_PATH_WEB_PREFIX + '/role/{id}/link']"
          >
            <svg-icon icon-class="perm"/>
          </el-button>

          <el-button
            type="primary"
            :icon="Edit"
            circle
            plain
            @click.stop="handleUpdate(scope.row)"
            v-hasPerm="[PUT + AUTH_PATH_WEB_PREFIX + '/role/{id}']"
          />
          <el-button
            type="danger"
            :icon="Delete"
            circle
            plain
            @click.stop="handleDelete(scope.row)"
            v-hasPerm="[DELETE + AUTH_PATH_WEB_PREFIX + '/role/list']"
          />
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页工具条 -->
    <pagination
      v-if="total > 0"
      :total="total"
      v-model:page="queryParams.current"
      v-model:limit="queryParams.pageSize"
      @pagination="handleQuery"
    />

    <!-- 表单弹窗 -->
    <el-dialog
      :title="dialog.title"
      v-model="dialog.visible"
      width="500px"
      destroy-on-close
    >
      <el-form
        ref="dataFormRef"
        :model="formData"
        :rules="rules"
        label-width="100px"
      >
        <el-form-item label="名称" prop="name">
          <el-input v-model="formData.name" placeholder="请输入角色名称"/>
        </el-form-item>

        <el-form-item label="编码" prop="authCode">
          <el-tree-select
            v-model="formData.authCode"
            placeholder="请选择角色"
            :data="authCodeOptions"
            filterable
            check-strictly
          />
        </el-form-item>

        <el-form-item label="数据权限" prop="dataScope">
          <el-tree-select
            v-model="formData.dataScope"
            placeholder="请选择数据权限"
            :data="dataScopeOptions"
            filterable
            check-strictly
          />
        </el-form-item>

        <template v-if="formData.dataScope === 'custom'">
          <el-form-item label="数据权限部门" prop="deptId">
            <el-tree-select
              v-model="formData.deptId"
              placeholder="请选择所属部门"
              :data="deptOptions"
              filterable
              check-strictly
              multiple
            />
          </el-form-item>
        </template>


        <el-form-item label="排序" prop="sort">
          <el-input-number
            v-model="formData.sort"
            controls-position="right"
            :min="0"
            style="width: 100px"
          />
        </el-form-item>

        <el-form-item label="状态">
          <el-radio-group v-model="formData.enabled">
            <el-radio :label="true">启用</el-radio>
            <el-radio :label="false">停用</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitFormData">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>

    <el-dialog
      :title="'【' + checkedRole.name + '】菜单权限分配'"
      v-model="resourceDialogVisible"
      width="1000px"
    >
      <el-scrollbar max-height="600px">
        <el-tree
          ref="resourceRef"
          node-key="value"
          show-checkbox
          :data="menuOptions"
          :default-expand-all="true"
        >

          <template #default="{ node, data }">
            <div v-if="data.isPerm" class="resource-tree-node">
              <div class="resource-tree-node__content">
                <el-checkbox
                  v-for="perm in permOptions.filter(
                    (perm) => perm.id === data.menuPermissionId
                  )"
                  :key="perm.value"
                  :label="perm.value"
                  v-model="perm.checked"
                  border
                  size="small"
                >{{ perm.label }}
                </el-checkbox
                >
              </div>
            </div>
            <span v-else>{{ node.label }}</span>
          </template>
        </el-tree>
      </el-scrollbar>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleRoleResourceSubmit"
          >确 定
          </el-button
          >
          <el-button @click="cancelResourceAssign">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
  import {nextTick, onMounted, reactive, ref, toRefs} from 'vue';
  import {
    listPageRoles,
    updateRole,
    getRoleFormDetail,
    addRole,
    deleteRoles,
    getRoleResourceIds,
    updateRoleMenu,
    roleAuthCodeOptions,
    roleDataScopeOptions,
  } from '@/api/system/role';
  import {getResource} from '@/api/system/menu';

  import {ElForm, ElMessage, ElMessageBox, ElTree} from 'element-plus';
  import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons-vue';
  import {
    RoleFormData,
    RolePage,
    RoleItem,
    RoleQueryParam,
  } from '@/types/api/system/role';
  import SvgIcon from '@/components/SvgIcon/index.vue';
  import {Option} from "@/types/common";
  // @ts-ignore
  import {POST, DELETE, PUT, PATCH, GET} from '@/types/store/prefix.d.ts';
  import {listSelectDepartments} from "@/api/system/dept";

  const emit = defineEmits(['roleClick']);
  const queryFormRef = ref(ElForm);
  const dataFormRef = ref(ElForm);
  const resourceRef = ref(ElTree);

  const state = reactive({
    loading: true,
    // 选中ID数组
    ids: [],
    // 非单个禁用
    single: true,
    // 非多个禁用
    multiple: true,
    queryParams: {
      current: 1,
      pageSize: 10,
    } as RoleQueryParam,
    roleList: [] as RolePage[],
    total: 0,
    dialog: {
      title: '',
      visible: false,
    },
    formData: {} as RoleFormData,
    rules: {
      name: [{required: true, message: '请输入角色名称', trigger: 'blur'}],
      code: [{required: true, message: '请输入角色编码', trigger: 'blur'}],
    },
    resourceDialogVisible: false,
    menuOptions: [] as any[],
    permOptions: [] as any[],
    checkStrictly: false,
    permGroupList: [],
    checkedRole: {
      id: '',
      name: '',
    }, // 选中的角色
    // 角色编码选项
    authCodeOptions: [] as Option[],
    // 数据权限选项
    dataScopeOptions: [] as Option[],
    // 部门树选项
    deptOptions: [] as Option[],
  });

  const {
    loading,
    multiple,
    queryParams,
    roleList,
    total,
    dialog,
    formData,
    rules,
    resourceDialogVisible,
    menuOptions,
    permOptions,
    checkedRole,
    checkStrictly,
    authCodeOptions,
    dataScopeOptions,
    deptOptions,
  } = toRefs(state);

  function handleQuery() {
    emit('roleClick', {});
    state.loading = true;
    listPageRoles(state.queryParams).then(({data}) => {
      state.roleList = data.list;
      state.total = data.total;
      state.loading = false;
    });
  }

  function resetQuery() {
    queryFormRef.value.resetFields();
    handleQuery();
  }

  function handleSelectionChange(selection: any) {
    state.ids = selection.map((item: any) => item.id);
    state.single = selection.length !== 1;
    state.multiple = !selection.length;
  }

  function handleRowClick(row: any) {
    emit('roleClick', row);
  }

  async function handleAdd() {
    await loadRoleCodeOptions();
    await loadDataScopeOptions();
    await loadDeptOptions();
    state.dialog = {
      title: '添加角色',
      visible: true,
    };
  }

  async function handleUpdate(row: any) {
    await loadRoleCodeOptions();
    await loadDataScopeOptions();
    await loadDeptOptions();
    state.dialog = {
      title: '修改角色',
      visible: true,
    };
    const roleId = row.id || state.ids;
    getRoleFormDetail(roleId).then(({data}) => {
      state.formData = data;
    });
  }

  function submitFormData() {
    dataFormRef.value.validate((valid: any) => {
      if (valid) {
        if (state.formData.id) {
          updateRole(state.formData.id as any, state.formData).then(() => {
            ElMessage.success('修改成功');
            cancel();
            handleQuery();
          });
        } else {
          addRole(state.formData).then(() => {
            cancel();
            ElMessage.success('新增成功');
            handleQuery();
          });
        }
      }
    });
  }

  /**
   * 弹窗关闭
   */
  function cancel() {
    state.dialog.visible = false;
    dataFormRef.value.resetFields();
  }

  /**
   *  删除
   */
  function handleDelete(row: any) {
    const ids = [row.id || state.ids].join(',');
    ElMessageBox.confirm('确认删除已选中的数据项?', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    })
      .then(() => {
        deleteRoles(ids).then(() => {
          ElMessage.success('删除成功');
          handleQuery();
        });
      })
      .catch(() => ElMessage.info('已取消删除'));
  }

  /**
   * 分配资源权限
   */
  function handleResourceAssign(row: RoleItem) {
    resourceDialogVisible.value = true;
    permOptions.value.map((item) => (item.checked = false));

    const roleId: any = row.id;
    checkedRole.value = {
      id: roleId,
      name: row.name,
    };
    //资源下拉数据
    getResource().then((response) => {
      state.menuOptions = response.data.menus;
      state.permOptions = response.data.perms;

      // 获取角色拥有的资源数据进行勾选
      getRoleResourceIds(roleId).then((res) => {
        const checkedMenuIds = res.data.menuIds;
        const checkedPermIds = res.data.menuPermissionIds;
        // 菜单勾选判断
        checkedMenuIds.map(item => resourceRef.value.setChecked(item, true))
        nextTick(() => {
          // 权限勾选判断
          permOptions.value.forEach((perm) => {
            if (checkedPermIds.includes(perm.value)) {
              perm.checked = true;
            } else {
              perm.checked = false;
            }
          });
        });
        checkStrictly.value = false; // 父子节点互相关联
      });
    });
  }

  /**
   * 提交资源权限
   */
  function handleRoleResourceSubmit() {
    const checkedMenuIds: any[] = resourceRef.value
      .getCheckedNodes(false, true)
      .map((node: any) => node.value);

    const checkedPermIds = state.permOptions
      .filter((item) => item.checked)
      .map((item) => item.value);

    const roleResourceData = {
      menuIds: checkedMenuIds,
      menuPermissionIds: checkedPermIds,
    };

    updateRoleMenu(checkedRole.value.id, roleResourceData).then((res) => {
      ElMessage.success('修改成功');
      state.resourceDialogVisible = false;
      handleQuery();
    });
  }

  // 取消资源分配
  function cancelResourceAssign() {
    state.resourceDialogVisible = false;
  }

  /**
   * 加载角色编码
   */
  async function loadRoleCodeOptions() {
    roleAuthCodeOptions().then((response) => {
      state.authCodeOptions = response.data;
    });
  }

  /**
   * 加载数据权限
   */
  async function loadDataScopeOptions() {
    roleDataScopeOptions().then((response) => {
      state.dataScopeOptions = response.data;
    });
  }

  /**
   * 加载部门
   */
  async function loadDeptOptions() {
    listSelectDepartments().then((response) => {
      state.deptOptions = response.data;
    });
  }

  onMounted(() => {
    handleQuery();
  });
</script>

<style lang="scss">
  .resource-tree-node {
    width: 100%;
    flex-wrap: wrap;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;
    margin-left: -28px !important;

    &__content {
      display: flex;
      flex-wrap: wrap;
    }

    .el-checkbox--default {
      background-color: transparent !important;
    }
  }

  .el-tree-node__content {
    height: auto !important;
  }

  .el-checkbox-group {
    display: flex;
    flex-wrap: wrap;

    &:hover {
      background-color: var(--el-tree-node-hover-bg-color);
    }

    &:active {
      background-color: var(--el-tree-node-hover-bg-color);
    }
  }

  .el-checkbox.el-checkbox--small {
    margin: 5px;
    z-index: 999;
    background: #fff;
  }
</style>
